scikit-learn机器学习简介

章节内容

在本节中,我们将介绍在scikit-learn中所使用的机器学习的词汇,并且给出一个简单的代码示例。.

机器学习:问题设置

通常,一个机器学习问题会考虑n个数据样本,然后尝试预测未知数据的属性。如果每个样本都不止一个属性的话,例如是一个多维条目(也称为多元 数据),则称其具有多个属性或特征

机器学习问题可分为以下几类:

  • 监督学习,数据包含有我们要预测的额外属性(单击此处 转到scikit-learn监督学习页面)。此问题可能是:

  • 分类:样本属于两个或多个类别,我们想从已经标记的数据中学习如何预测未标记数据的类别。分类问题的一个例子是手写数字识别,手写数字识别的目的是将每个输入向量分配给有限的离散类别中的一个。另一种思考分类问题的方法是作为一种离散的(与连续相反)监督学习形式,它有有限的类别,并且对于所提供的n个样本中的每个样本,尝试使用正确的类别来标记。

  • 回归:如果所期待的输出包含一个或多个连续变量,则该任务称为回归。回归问题的一个例子是根据鲑鱼的年龄和体重来预测其长度。

  • 无监督学习,其中训练数据由一组输入向量x组成,没有任何对应的目标值。此类问题的目标是在所有数据内发现相似数据(被称为聚类),或者确定输入空间内数据的分布(被称为 密度估计),或是为了可视化,将高维空间的数据投影到2维或3维 (单击此处 可转到Scikit-Learn无监督学习页面)。

训练集和测试集

机器学习是学习数据集的某些属性,然后针对另一个数据集测试这些属性。机器学习中的一种常见做法是通过将数据集分为两部分来评估算法。我们称其中一部分为训练集,在该训练集上我们学习一些属性;我们将另一部分称为测试集,在其上面来测试学习到的属性。

加载示例数据集

scikit-learn包括一些标准数据集,例如 用于分类的 鸢尾属植物数据集手写数字识别数据集和用于回归的波士顿房价数据集

接下来,我们从shell中启动Python解释器,然后加载鸢尾属植物手写数字识别数据集。我们约定符号 $是表示shell提示,而>>>表示Python解释器提示:

    $ python
    >>> from sklearn import datasets
    >>> iris = datasets.load_iris()
    >>> digits = datasets.load_digits()

数据集是一个类似于字典的对象,其中包含所有数据和有关该数据的一些元数据。此数据存储在.data成员中,该成员是一个数组。在监督问题的情况下,一个或多个响应变量存储在成员中。有关不同数据集的更多详细信息,请参见数据集加载部分

例如,对于手写数字识别数据集,digits.data方法可以访问用于数字样本分类的特征:

>>> print(digits.data)
    [[ 0.   0.   5. ...   0.   0.   0.]
     [ 0.   0.   0. ...  10.   0.   0.]
     [ 0.   0.   0. ...  16.   9.   0.]
     ...
     [ 0.   0.   1. ...   6.   0.   0.]
     [ 0.   0.   2. ...  12.   0.   0.]
     [ 0.   0.  10. ...  12.   1.   0.]]

digits.target给出数字数据集的对应类别,即与我们尝试学习每个数字图像相对应的类别:

>>> digits.target
    array([0, 1, 2, ..., 8, 9, 8])

数据数组的shape(形状)

该数据始终是2维数组(n_samples, n_features),虽然原始数据可能具有不同的形状,但对于手写数字识别数据集来说,每个样本都是8x8的图像,可以使用以下代码访问:

>>> digits.images[0]
    array([[  0.,   0.,   5.,  13.,   9.,   1.,   0.,   0.],
           [  0.,   0.,  13.,  15.,  10.,  15.,   5.,   0.],
           [  0.,   3.,  15.,   2.,   0.,  11.,   8.,   0.],
           [  0.,   4.,  12.,   0.,   0.,   8.,   8.,   0.],
           [  0.,   5.,   8.,   0.,   0.,   9.,   8.,   0.],
           [  0.,   4.,  11.,   0.,   1.,  12.,   7.,   0.],
           [  0.,   2.,  14.,   5.,  10.,  12.,   0.,   0.],
           [  0.,   0.,   6.,  13.,  10.,   0.,   0.,   0.]])

数据集上的一个简单示例说明了如何在scikit-learn上加载原始问题数据集和处理数据。(意译)

从外部数据集加载

要从外部数据集加载,请参阅加载外部数据集

学习和预测

对于手写数字识别数据集,任务是在给定图像的情况下预测其代表的数字。我们为10种可能的类别(从零到九的数字)中的每一种提供了样本,我们在其上拟合了一个 估计器(estimator),使其能够预测 还未见样本所属的类别。

在scikit-learn中,分类的一个估计器(estimator)是一个Python对象,该对象实现fit(X, y)predict(T)方法

估计器(estimator)的一个示例是类sklearn.svm.SVC,它实现支持向量机分类。估计器(estimator)的构造函数的参数作为模型的参数。

目前,我们暂且将估计器(estimator)视为黑匣子:

>>> from sklearn import svm
>>> clf = svm.SVC(gamma=0.001, C=100.)

选择模型的参数

在此示例中,我们手动设置gamma的值。要为这些参数找到合适的值,我们可以使用诸如网格搜索交叉验证之类的工具。

首先将clf(分类器)估计器实例拟合到模型;也就是说,它必须从模型中学习。我们通过把训练集传递给fit方法来完成学习。对于训练集来说,我们将使用数据集中除了最后一个的所有图像,我们对最后一个图形进行预测。我们使用[:-1]Python语法来选择训练集,这将产生一个新数组,该数组包含来自digits.data除最后一项之外的所有数据:

>>> clf.fit(digits.data[:-1], digits.target[:-1])
SVC(C=100.0, gamma=0.001)

现在您可以预测新的值。在这种情况下,您对digits.data的最后一张图片进行预测。通过预测,您将确定与来自训练集中最后一张图像最匹配的类别。

>>> clf.predict(digits.data[-1:])
array([8])

相应的图像是:

正如您所见,这是一项极具挑战的任务:毕竟,图像的分辨率很差。您是否同意该分类器(的分类结果)?

您可以运行和研究一个有关此分类问题的完整示例: 识别手写数字

模型持久化

可以使用Python的内置持久性模型pickle在scikit-learn中保存模型:

>>> from sklearn import svm
>>> from sklearn import datasets
>>> clf = svm.SVC()
>>> X, y = datasets.load_iris(return_X_y=True)
>>> clf.fit(X, y)
SVC()
>>> import pickle
>>> s = pickle.dumps(clf)
>>> clf2 = pickle.loads(s)
>>> clf2.predict(X[0:1])
array([0])
>>> y[0]
0

在scikit-learn的特定情况下,人们可能会使用joblib替代pickle(joblib.dumpjoblib.load),后者在大数据上效率更高,但它只能在磁盘进行pickle而不是字符串上:

>>> from joblib import dump, load
>>> dump(clf, 'filename.joblib') 

之后,您可以使用以下方法重新加载pickle模型(可以在另一个Python进程中):

>>> clf = load('filename.joblib') 

注意

joblib.dumpjoblib.load方法也接受类似文件的对象,而不是文件名。有关Joblib的数据持久性的更多信息,请参见此处

请注意,pickle 存在一些安全性和可维护性问题。有关scikit-learn的模型持久性的更多详细信息,请参阅模型持久性部分。

约定

scikit-learn估计器(estimator)遵循某些规则,以使其行为更具预测性。在 通用术语表和API元素中更详细地描述了这些内容。

类型转换

除非另有说明,否则输入将会被强制转换为float64:

>>> import numpy as np
>>> from sklearn import random_projection
>>> rng = np.random.RandomState(0)
>>> X = rng.rand(10, 2000)
>>> X = np.array(X, dtype='float32')
>>> X.dtype
dtype('float32')

>>> transformer = random_projection.GaussianRandomProjection()
>>> X_new = transformer.fit_transform(X)
>>> X_new.dtype
dtype('float64')

在此示例中,原本类型为float32X通过fit_transform(X)方法强制转换float64

回归问题的输出将会被强制转换为float64,分类问题的输出维持不变:

>>> from sklearn import datasets
>>> from sklearn.svm import SVC
>>> iris = datasets.load_iris()
>>> clf = SVC()
>>> clf.fit(iris.data, iris.target)
SVC()
>>> list(clf.predict(iris.data[:3]))
[0, 0, 0]

>>> clf.fit(iris.data, iris.target_names[iris.target])
SVC()

>>> list(clf.predict(iris.data[:3]))
['setosa', 'setosa', 'setosa']

第一次调用predict()返回一个整型数组,因为训练时使用的iris.target是一个整型数组。第二次调用predict()返回一个字符串数组,因为训练时使用的是iris.target_names

重新训练和更新参数

通过set_params()方法可以更新估计器(estimator)的超参数。多次调用fit()方法将会覆盖以前调用fit()学习到任何内容:

>>> import numpy as np
>>> from sklearn.datasets import load_iris
>>> from sklearn.svm import SVC
>>> X, y = load_iris(return_X_y=True)
>>> clf = SVC()
>>> clf.set_params(kernel='linear').fit(X, y)
SVC(kernel='linear')
>>> clf.predict(X[:5])
array([0, 0, 0, 0, 0])

>>> clf.set_params(kernel='rbf').fit(X, y)
SVC()
>>> clf.predict(X[:5])
array([0, 0, 0, 0, 0])

在构造估计器(estimator)之后,默认值为rbf的kernel首先通过 SVC.set_params()方法更改为linear,然后又把kernel更改回rbf来重新训练估计器(estimator)并进行第二次预测。

多类与多标签训练

在使用multiclass classifiers时,执行的学习和预测任务取决于适合的目标数据的格式:

>>> from sklearn.svm import SVC
>>> from sklearn.multiclass import OneVsRestClassifier
>>> from sklearn.preprocessing import LabelBinarizer

>>> X = [[1, 2], [2, 4], [4, 5], [3, 2], [3, 1]]
>>> y = [0, 0, 1, 1, 2]

>>> classif = OneVsRestClassifier(estimator=SVC(random_state=0))
>>> classif.fit(X, y).predict(X)
array([0, 0, 1, 1, 2])

在上述情况下,分类器在一维多类标签数组下进行训练,因此predict()方法提供了相应的多类预测。也有可能在二元指示器(binary label indicators)的二维数组上训练:

>>> y = LabelBinarizer().fit_transform(y)
>>> classif.fit(X, y).predict(X)
array([[1, 0, 0],
       [1, 0, 0],
       [0, 1, 0],
       [0, 0, 0],
       [0, 0, 0]])

分类器是在一个2维二元数组y上 使用LabelBinarizer进行训练fit()的。在这种情况下,predict()将返回一个二维数组,该数组代表相应的多标签预测。

请注意,第四和第五个实例返回的全为零,表明它们与三个标签都不匹配fit。使用多标签输出,也可以为一个实例分配多个标签:

>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> y = [[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]]
>>> y = MultiLabelBinarizer().fit_transform(y)
>>> classif.fit(X, y).predict(X)
array([[1, 1, 0, 0, 0],
       [1, 0, 1, 0, 0],
       [0, 1, 0, 1, 0],
       [1, 0, 1, 0, 0],
       [1, 0, 1, 0, 0]])

在这种情况下,分类器在每个分配了多个标签的实例上进行训练。MultiLabelBinarizer方法用于二值化2维数组以便进行fit。结果, predict()方法为每个实例返回带有多个预测标签的二维数组。

©2007-2019,scikit-learn开发人员(BSD许可证)。 显示此页面源码